package com.atguigu.aops;

import com.atguigu.annotations.MethodExporter;
import com.fasterxml.jackson.databind.ObjectMapper;
import jakarta.servlet.http.HttpServletRequest;
import lombok.extern.slf4j.Slf4j;
import org.aspectj.lang.ProceedingJoinPoint;
import org.aspectj.lang.annotation.Around;
import org.aspectj.lang.annotation.Aspect;
import org.aspectj.lang.reflect.MethodSignature;
import org.springframework.core.DefaultParameterNameDiscoverer;
import org.springframework.stereotype.Component;
import org.springframework.web.context.request.RequestAttributes;
import org.springframework.web.context.request.RequestContextHolder;
import org.springframework.web.context.request.ServletRequestAttributes;

import java.lang.reflect.Method;

/**
 * @Author: shenhao
 * @CreatTime: 2024/11/4 8:36 score
 * @Version: 1.0
 * 高可用, 高并发, 高性能 高并发可以实时起效, 迅速想到redis+lua脚本综合使用
 */
@Aspect
@Component
@Slf4j
public class MethodExporterAspect {
    //容器捞鱼，谁带着使用了MethodExporter注解将会触发Around业务逻辑
    @Around("@annotation(com.atguigu.annotations.MethodExporter)")
    public Object methodExporter(ProceedingJoinPoint joinPoint) throws Throwable {
        Object retVal = null;
        System.out.println("-----@Around method start MethodExporter-----");
        long startTime = System.currentTimeMillis();
        retVal = joinPoint.proceed();
        long endTime = System.currentTimeMillis();
        long costTime = endTime - startTime;
        //  获取请求对象 RequestContextHolder 类持有上下文的 Request容器。
        RequestAttributes requestAttributes = RequestContextHolder.getRequestAttributes();
        //  转化为ServletRequestAttributes 然后可以获取request 和 response 对象
        ServletRequestAttributes servletRequestAttributes = (ServletRequestAttributes) requestAttributes;
        HttpServletRequest request = servletRequestAttributes.getRequest();
        //1 获得重载后的方法名
        MethodSignature signature = (MethodSignature) joinPoint.getSignature();
        Method method = signature.getMethod();
        //2 确定方法名后获得该方法上面配置的注解标签MyRedisCache
        MethodExporter methodExporter = method.getAnnotation(MethodExporter.class);
        if (methodExporter != null) {
            //3 获得方法里面的形参信息
            StringBuffer jsonInputParams = new StringBuffer();
            Object[] args = joinPoint.getArgs();
            DefaultParameterNameDiscoverer discoverer = new DefaultParameterNameDiscoverer();
            String[] paramNames = discoverer.getParameterNames(method);
            for (int i = 0; i < paramNames.length; i++) {
                jsonInputParams.append(paramNames[i]);
                jsonInputParams.append("\t").append(args[i].toString()).append(";");
            }
            String jsonResult=null;
            if (retVal!=null){
                jsonResult = new ObjectMapper().writeValueAsString(retVal);
            }else {
                jsonResult = "null";
            }
            log.info("\n方法分析上报中 \n方法的请求路径为:{} \n类名方法名:{}.{}()\n执行耗时:{}毫秒\n输入参数:{}\n返回结果:{}\nover", request.getRequestURL(), joinPoint.getTarget().getClass().getName(), joinPoint.getSignature().getName(), costTime, jsonInputParams, jsonResult);
        }
        System.out.println("-----@Around method end MethodExporter-----");
        return retVal;
    }
}
